// ChatSessionServiceImpl.java
package com.ruoyi.chatAi.service.impl;

import com.ruoyi.chatAi.domain.ChatMessage;
import com.ruoyi.chatAi.domain.ChatSession;
import com.ruoyi.chatAi.mapper.ChatSessionMapper;
import com.ruoyi.chatAi.service.ChatMessageService;
import com.ruoyi.chatAi.service.ChatSessionService;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.uuid.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.model.Media;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.MimeType;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.publisher.Flux;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;

/**
 * 聊天会话服务实现类
 *
 * @author ruoyi
 */
@Service
@Transactional(rollbackFor = Exception.class) // 添加类级别的事务注解，所有方法都会应用
public class ChatSessionServiceImpl implements ChatSessionService {
    private static final Logger log = LoggerFactory.getLogger(ChatSessionServiceImpl.class);

    @Autowired
    private ChatSessionMapper chatSessionMapper;

    @Autowired
    private ChatMessageService chatMessageService;

    @Autowired
    private ChatClient chatClient;

    @Value("${ruoyi.profile}")
    private String fileBaseDir;

    @Override
    @Transactional(readOnly = true)
    public List<ChatSession> selectChatSessionsByUserId(Long userId) {
        return chatSessionMapper.selectChatSessionsByUserId(userId);
    }

    @Override
    public String insertChatSession(ChatSession chatSession) {
        if (chatSession.getSessionId() == null || chatSession.getSessionId().isEmpty()) {
            chatSession.setSessionId(UUID.randomUUID().toString());
        }

        if (chatSession.getStatus() == null || chatSession.getStatus().isEmpty()) {
            chatSession.setStatus("0"); // 0表示正常
        }

        chatSession.setCreateTime(DateUtils.getNowDate());
        chatSession.setUpdateTime(DateUtils.getNowDate());

        if (chatSession.getCreateBy() == null || chatSession.getCreateBy().isEmpty()) {
            chatSession.setCreateBy(SecurityUtils.getUsername());
        }

        chatSessionMapper.insertChatSession(chatSession);
        return chatSession.getSessionId();
    }

    @Override
    public int updateChatSession(ChatSession chatSession) {
        chatSession.setUpdateTime(DateUtils.getNowDate());
        return chatSessionMapper.updateChatSession(chatSession);
    }

    @Override
    public int deleteChatSessionByIds(String[] sessionIds) {
        return chatSessionMapper.deleteChatSessionByIds(sessionIds);
    }

    @Override
    public int deleteChatSessionById(String sessionId) {
        return chatSessionMapper.deleteChatSessionById(sessionId);
    }


    @Override
    public SseEmitter generate(ChatSession chatSession) {
        // String message = chatSession.getMessages().get(0).getContent();
       /* System.out.println(chatSession);
        return null;*/
        return generateWithSession(chatSession);
    }

    @Override
    public SseEmitter generateWithSession(ChatSession chatSession) {
        SseEmitter emitter = new SseEmitter(180000L);
        try {
            Long userId = chatSession.getUserId();
            String userName = chatSession.getCreateBy();
            String message = chatSession.getMessages().get(0).getContent();
            final String finalSessionId = createOrGetSession
                    (chatSession.getSessionId(), message, userId, userName);
            //是否包含文件
            Boolean isFile = chatSession.getMessages().get(0).getIsFileMessage();
            List<ChatMessage.FileInfo> files = chatSession.getMessages().get(0).getFiles();

            ExecutorService executor = Executors.newSingleThreadExecutor();
            executor.execute(() -> {
                try {
                    if (isFile) {
                        processAiResponse(finalSessionId, message, emitter, userId, userName, files);

                    } else {
                        processAiResponse(finalSessionId, message, emitter, userId, userName, null);
                    }
                } catch (Exception e) {
                    log.error("处理AI响应失败: ", e);
                    emitter.completeWithError(e);
                }
            });
            // 设置emitter的关闭处理器
            setupEmitterCloseHandlers(emitter, executor, finalSessionId);
            return emitter;
        } catch (Exception e) {
            log.error("创建会话或初始消息失败: ", e);
            emitter.completeWithError(e);
            return emitter;
        }
    }

    /**
     * 创建新会话或获取现有会话，并保存用户消息
     * 在当前事务中执行
     */
    private String createOrGetSession(String sessionId, String message, Long userId, String userName) {
        // 如果没有会话ID，创建新会话
        if (sessionId == null || sessionId.isEmpty()) {
            ChatSession newSession = new ChatSession();
            newSession.setUserId(userId);
            newSession.setTitle(generateSessionTitle(message));
            newSession.setStatus("0"); // 正常状态
            newSession.setCreateBy(userName);
            sessionId = insertChatSession(newSession);
        }

        // 保存用户消息
        ChatMessage userMessage = new ChatMessage();
        userMessage.setSessionId(sessionId);
        userMessage.setUserId(userId);
        userMessage.setRole("user");
        userMessage.setContent(message);
        userMessage.setTokens(chatMessageService.estimateTokens(message));
        userMessage.setCreateBy(userName);
        chatMessageService.insertChatMessage(userMessage);

        return sessionId;
    }

    /**
     * 处理AI响应
     * 在事务外部的异步任务中执行
     */
    private void processAiResponse(String sessionId, String userMessage, SseEmitter emitter,
                                   Long userId, String userName, List<ChatMessage.FileInfo> files) {
        try {

            // 创建AI消息记录
            ChatMessage aiMessage = new ChatMessage();
            aiMessage.setSessionId(sessionId);
            aiMessage.setUserId(userId);
            aiMessage.setRole("assistant");
            aiMessage.setContent("");
            aiMessage.setTokens(0);
            aiMessage.setCreateBy(userName);

            // 保存初始空消息，获取消息ID
            chatMessageService.insertChatMessage(aiMessage);
            Long aiMessageId = aiMessage.getMessageId();

            StringBuilder aiReplyBuilder = new StringBuilder();
            // 获取流式响应
            Flux<String> contents =null;
            if (files != null && !files.isEmpty()) {
                List<Media> medias = handleFile(files);
                contents = chatClient.prompt()
                        .user(p -> p.text(userMessage).media(medias.toArray(Media[]::new)))
                        .advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId))
                        .stream()
                        .content();

            } else {
                contents = chatClient.prompt()
                        .user(userMessage)
                        .advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId))
                        .stream()
                        .content();
            }
            emitter.send("[START]|" + sessionId);
            contents.subscribe(
                    chunk -> {
                        try {
                            emitter.send(chunk, MediaType.TEXT_EVENT_STREAM);
                            aiReplyBuilder.append(chunk);
                        } catch (IOException e) {
                            log.error("发送数据块失败: ", e);
                            emitter.completeWithError(e);
                        }
                    },
                    error -> {
                        log.error("AI响应出错: ");
                        // 确保即使出错也保存已收到的内容
                        updateAiMessageContent(aiMessageId, aiReplyBuilder.toString(), userName);
                        emitter.completeWithError(error);
                    },
                    () -> {
                        try {
                            String fullAiReply = aiReplyBuilder.toString();
                            // 最终更新完整回复
                            updateAiMessageContent(aiMessageId, fullAiReply, userName);
                            emitter.send("[DONE]", MediaType.TEXT_EVENT_STREAM);
                            emitter.complete();
                        } catch (IOException e) {
                            log.error("完成响应失败: ", e);
                            emitter.completeWithError(e);
                        }
                    }
            );
        } catch (Exception e) {
            log.error("处理AI响应过程中发生错误: ", e);
            emitter.completeWithError(e);
        }
    }

    /**
     * 设置emitter的关闭处理器
     */
    private void setupEmitterCloseHandlers(SseEmitter emitter, ExecutorService executor, String sessionId) {
        emitter.onTimeout(() -> {
            log.warn("会话 {} 超时", sessionId);
            emitter.complete();
            executor.shutdown();
        });

        emitter.onError((e) -> {
            log.error("会话 {} 发生错误: {}", sessionId, e.getMessage());
            emitter.completeWithError(e);
            executor.shutdown();
        });

        emitter.onCompletion(() -> {
            log.debug("会话 {} 已完成", sessionId);
            emitter.complete();
            executor.shutdown();
        });
    }


    @Override
    public String generateSessionTitle(String message) {
        return chatClient.prompt().user("对以下内容生成简短标题:" + message).call().content();
    }

    /**
     * 更新AI消息内容
     */
    private void updateAiMessageContent(Long messageId, String content, String userName) {
        try {
            if (messageId == null || content == null) {
                log.warn("更新AI消息内容失败：消息ID或内容为空");
                return;
            }

            ChatMessage updateMessage = new ChatMessage();
            updateMessage.setMessageId(messageId);
            updateMessage.setContent(content);
            updateMessage.setTokens(chatMessageService.estimateTokens(content));
            updateMessage.setUpdateTime(DateUtils.getNowDate());
            updateMessage.setUpdateBy(userName);

            chatMessageService.updateChatMessage(updateMessage);
            log.debug("更新AI消息内容成功, ID={}, 内容长度={}", messageId, content.length());
        } catch (Exception e) {
            log.error("更新AI消息内容失败: messageId={}", messageId, e);
        }
    }


    private List<Media> handleFile(List<ChatMessage.FileInfo> fileInfos) {
        List<Media> medias = new ArrayList<>();
        List<MultipartFile> multipartFiles = new ArrayList<>();

        for (ChatMessage.FileInfo fileInfo : fileInfos) {
            String path = fileInfo.getPath();

            // 使用强力正则表达式处理各种可能的 profile 前缀
            path = path.replaceAll("^/*profile/*", "");

            // 确保路径不以 / 开头，避免双斜杠问题
            if (path.startsWith("/")) {
                path = path.substring(1);
            }

            // 直接使用注入的 fileBaseDir 构建完整路径，避免双斜杠
            String fullPath = fileBaseDir;
            if (!fileBaseDir.endsWith("/")) {
                fullPath += "/";
            }
            fullPath += path;

            File file = new java.io.File(fullPath);

            if (file.exists()) {
                try {
                    // 获取文件内容类型
                    String contentType = Files.probeContentType(file.toPath());
                    if (contentType == null) {
                        contentType = "application/octet-stream";
                    }

                    // 获取文件名
                    String fileName = file.getName();

                    // 读取文件内容
                    byte[] fileContent = Files.readAllBytes(file.toPath());

                    // 创建 MockMultipartFile
                    MockMultipartFile mockFile = new MockMultipartFile(
                            "file", // 表单字段名
                            fileName, // 原始文件名
                            contentType, // 内容类型
                            fileContent // 文件内容
                    );

                    // 添加到列表
                    multipartFiles.add(mockFile);


                } catch (IOException e) {
                    log.error("读取文件失败: {}", fullPath, e);
                }
            } else {
                log.warn("文件不存在: {}", fullPath);
            }
        }

        medias = multipartFiles.stream()
                .map(file -> new Media(
                                MimeType.valueOf(Objects.requireNonNull(file.getContentType())),
                                file.getResource()
                        )
                )
                .toList();

        return medias;
    }


}